package com.util.config.validator;


import cn.hutool.core.util.ArrayUtil;
import com.util.config.HttpResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;

import javax.validation.ConstraintViolation;
import java.io.Serializable;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * 参数验证 辅助类
 * <p>
 * eg:
 * 字段注解 @NotNull(message = "1001=当前门店为空")
 * 返回HttpResult异常：code为1001 异常描述：当前门店为空
 * </p>
 *
 * @author ljgLiu
 * @date 2020-03-13 15:03
 */
@Slf4j
public class ValidatorUtil {

    /**
     * 默认异常码
     */
    public static final String DEFAULT_ERROR_CODE = "FAIL";

    /**
     * 错误搜集
     *
     * @param violations
     * @return
     */
    public static Map<String, String> validHandlerResult(Set<ConstraintViolation<?>> violations) {
        if (violations == null) {
            return null;
        }
        Map<String, String> errorMsgMap = new LinkedHashMap<>(10);
        // 异常信息code:msg
        StringBuilder defaultErrorMsg = new StringBuilder(violations.size() * 10);
        String errorMsg, fieldName;
        for (ConstraintViolation<?> item : violations) {
            errorMsg = item.getMessage();
            fieldName = item.getPropertyPath().toString();
            analyzeMsg(errorMsg, fieldName, errorMsgMap, defaultErrorMsg);
        }
        // 默认异常
        setDefaultErrorMsg(errorMsgMap, defaultErrorMsg.toString());
        return errorMsgMap;
    }

    /**
     * 针对Spring valid错误搜集
     *
     * @param bindingResult
     * @return
     */
    public static Map<String, String> validHandlerBindingResult(BindingResult bindingResult) {
        if (bindingResult == null || !bindingResult.hasErrors()) {
            return null;
        }
        List<FieldError> fieldErrors = bindingResult.getFieldErrors();
        Map<String, String> errorMsgMap = new LinkedHashMap<>(10);
        // 异常信息code:msg
        StringBuilder defaultErrorMsg = new StringBuilder(fieldErrors.size() * 10);
        String errorMsg, fieldName;
        for (FieldError fieldError : fieldErrors) {
            errorMsg = fieldError.getDefaultMessage();
            fieldName = fieldError.getField();
            analyzeMsg(errorMsg, fieldName, errorMsgMap, defaultErrorMsg);
        }
        // 默认异常
        setDefaultErrorMsg(errorMsgMap, defaultErrorMsg.toString());
        return errorMsgMap;
    }

    /**
     * 解析异常信息 [消息格式：错误码=消息内容]
     *
     * @param errorMsg
     * @param fieldName
     * @param errorMsgMap
     * @param defaultMsg
     */
    public static void analyzeMsg(String errorMsg, String fieldName, Map<String, String> errorMsgMap, StringBuilder defaultMsg) {
        String[] items = StringUtils.split(errorMsg, "=");
        if (items != null) {
            String errorCode = items[0];
            errorMsg = items[1];
            errorMsgMap.put(errorCode, errorMsg);
        } else {
            // 常规异常
            defaultMsg.append(errorMsg).append("|");
        }
    }

    /**
     * 设置默认异常信息
     *
     * @param errorMsgMap
     * @param defaultErrorMsg
     */
    public static void setDefaultErrorMsg(Map<String, String> errorMsgMap, String defaultErrorMsg) {
        if (errorMsgMap.isEmpty()) {
            if (defaultErrorMsg.length() > 0) {
                errorMsgMap.put(DEFAULT_ERROR_CODE, defaultErrorMsg.substring(0, defaultErrorMsg.length() - 1));
            }
        }
    }

    /**
     * 针对返回SoaResponse<br>
     * 返回错误：错误列表第一项
     *
     * @param violations
     * @param <T>
     * @return
     */
    public static <T extends Serializable> HttpResult<T> buildResponse(Set<ConstraintViolation<T>> violations) {
        if (ArrayUtil.isNotEmpty(violations)) {
            HttpResult<T> response = new HttpResult<>();
            Map<String, String> errorMsgMap = validHandlerResult(convertGenericToUnknown(violations));
            if (errorMsgMap != null && errorMsgMap.size() > 0) {
                // 取出第一项
                Map.Entry<String, String> entryMsg = errorMsgMap.entrySet().iterator().next();
                response.setCode(entryMsg.getKey());
                response.setMsg(entryMsg.getValue());
                // TODO:api待设置传递的信息
                return response;
            }
        }
        return null;
    }

    /**
     * 类型转换 T > ?
     *
     * @param violations
     * @param <T>
     * @return
     */
    public static <T> Set<ConstraintViolation<?>> convertGenericToUnknown(Set<ConstraintViolation<T>> violations) {
        if (ArrayUtil.isEmpty(violations)) {
            return null;
        }
        Set<ConstraintViolation<?>> violationSet = new HashSet();
        for (ConstraintViolation<T> item : violations) {
            violationSet.add(item);
        }
        return violationSet;
    }

    /**
     * 类型转换 ? to Object
     *
     * @param violations
     * @return
     */
    public static Set<ConstraintViolation<Object>> convertUnknownToObject(Set<ConstraintViolation<?>> violations) {
        if (ArrayUtil.isEmpty(violations)) {
            return null;
        }
        Set<ConstraintViolation<Object>> violationSet = new HashSet();
        for (ConstraintViolation<?> item : violations) {
            violationSet.add((ConstraintViolation<Object>) item);
        }
        return violationSet;
    }


}

